#define _CRT_SECURE_NO_WARNINGS 1

// 文件操作

// 对比一组函数
// scanf/fscanf/sscanf
// printf/fprintf/sprintf

// scanf针对标准输入（键盘）的格式化输入函数
// printf针对标准输出（屏幕）的格式化输出函数

// fscanf针对所有输入流的格式化输入函数
// fprintf针对所有输出流的格式化输出函数

// sscanf
// // 在字符串中读取一个格式化的数据
// int sscanf(const char* s, const char* format, ...);

// sprintf
// // 把格式化的数据转化成字符串
// int sprintf ( char * str, const char * format, ... );

//#include <stdio.h>
//
//struct S 
//{
//	char name[20];
//	int age;
//	float score;
//};
//
//int main()
//{
//	struct S s = { "ZhangSan", 20, 85.5f };
//	struct S tmp = { 0 };
//
//
//	char arr[100] = { 0 };
//
//	sprintf(arr, "%s %d %f", s.name, s.age, s.score);
//	printf("%s\n", arr);
//
//	sscanf(arr, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));
//	printf("%s %d %f\n", tmp.name, tmp.age, tmp.score);
//
//	return 0;
//}

// 文件的随机读写
// 根据文件指针的位置和偏移量来定位文件指针（文件内容的光标）
// int fseek ( FILE * stream, long int offset, int origin );

//#include <stdio.h>
//
//int main()
//{
//	FILE* pf = fopen("data.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	int ch = fgetc(pf); // a
//	printf("%c\n", ch);
//
//	ch = fgetc(pf); // b
//	printf("%c\n", ch);
//
//	ch = fgetc(pf); // c
//	printf("%c\n", ch);
//
//	ch = fgetc(pf); // d
//	printf("%c\n", ch);
//	
//	// 返回离起始位置多少偏移量
//	int n = ftell(pf);
//	printf("%d\n", n);
//
// // 想让光标到哪里就到哪里，起始位置有三个选择
//	fseek(pf, 0, SEEK_SET);
//	// fseek(pf, -4, SEEK_CUR);
//	// fseek(pf, -6, SEEK_END);
//	ch = fgetc(pf); // a
//	printf("%c\n", ch);
//
//	return 0;
//}

// void rewind ( FILE * stream );
// 光标回到起始点



// 文件读取结束的判定
// 被错误使用的feof

// 在文件读取的过程中，不能用feof的返回值来直接判断文件是否结束
// feof的作用是：当文件读取结束的时候，判断是读取结束的原因是遇到文件尾结束
// ferrot的作用是：当文件读取结束的时候，判断是读取结束的原因是遇到错误结束

// 判断是否结束
// 文本文件读取是否结束，判断返回值为EOF（fgetc）或者NULL（fgets）
// 比如fgetc判断是否为EOF
// fgets判断返回值是否为NULL
//#include <stdio.h>
//#include <stdlib.h>

//int main(void)
//{
//    int c; // 注意：int，非char，要求处理EOF
//    FILE* fp = fopen("test.txt", "r");
//    if (!fp) {
//        perror("File opening failed");
//        return EXIT_FAILURE;
//    }
//    //fgetc 当读取失败的时候或者遇到文件结束的时候，都会返回EOF
//    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
//    {
//        putchar(c);
//    }
//    //判断是什么原因结束的
//    if (ferror(fp))
//        puts("I/O error when reading");
//    else if (feof(fp))
//        puts("End of file reached successfully");
//
//    fclose(fp);
//}


// fread判断返回值是否小于实际要读的个数
// #include <stdio.h>
//
//enum { SIZE = 5 };
//
//int main(void)
//{
//    double a[SIZE] = { 1.,2.,3.,4.,5. };
//    FILE* fp = fopen("test.bin", "wb"); // 必须用二进制模式
//
//    fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
//    fclose(fp);
//
//    double b[SIZE];
//    fp = fopen("test.bin", "rb");
//    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
//    if (ret_code == SIZE) {
//        puts("Array read successfully, contents: ");
//        for (int n = 0; n < SIZE; ++n)
//            printf("%f ", b[n]);
//        putchar('\n');
//    }
//    else { // error handling
// //	  判断读取不正确原因
//        if (feof(fp))
//            printf("Error reading test.bin: unexpected end of file\n");
//        else if (ferror(fp)) {
//            perror("Error reading test.bin");
//        }
//    }
//
//    fclose(fp);
//}


// 文件缓冲区
// ANSIC采用缓冲文件系统来处理数据文件，所谓缓冲文件熊就是指系统自动在内存中为程序每一个正在使用的文件开辟一块文件缓冲区
// 从内存向磁盘输出数据会先送到内存中的缓冲区，装满缓冲区后才一起送到磁盘上
// 如果从磁盘向计算机读入数据，则从磁盘文件中读取数据输入到内存缓冲区（充满缓冲区）
// 然后再从缓冲区逐个地将数据送到程序数据区（程序变量等）。缓冲区的大小根据C编译系统决定的
//#include <stdio.h>
//#include <windows.h>
////VS2022 WIN11环境测试
//
//int main()
//{
//    FILE* pf = fopen("test.txt", "w");
//    fputs("abcdef", pf);//先将代码放在输出缓冲区
//    printf("睡眠10秒-已经写数据了，打开test.txt文件，发现文件没有内容\n");
//    Sleep(10000);
//    printf("刷新缓冲区\n");
//
//    fflush(pf);//刷新缓冲区时，才将输出缓冲区的数据写到文件（磁盘）
//    //注：fflush 在高版本的VS上不能使用了
//    printf("再睡眠10秒-此时，再次打开test.txt文件，文件有内容了\n");
//    Sleep(10000);
//
//    fclose(pf);
//    //注：fclose在关闭文件的时候，也会刷新缓冲区
//    pf = NULL;
//
//    return 0;
//}

